package edu.utn.tacs.grupouno.dao.implementations;

import java.util.Date;
import java.util.List;

import javax.jdo.JDOHelper;
import javax.jdo.PersistenceManager;
import javax.jdo.PersistenceManagerFactory;
import javax.jdo.Query;

import edu.utn.tacs.grupouno.dao.AbstractTurnoContainer;
import edu.utn.tacs.grupouno.exception.TurnoNoDisponibleException;
import edu.utn.tacs.grupouno.negocio.Dia;
import edu.utn.tacs.grupouno.negocio.Turno;
import edu.utn.tacs.grupouno.negocio.TurnoSemanal;

public class AppEngineJDOTurnoContainer extends AbstractTurnoContainer {
	private PersistenceManagerFactory persistenceManagerFactory;
	
	@Override
	public void addTurnoAsignado(Date date, Turno turno) {
		PersistenceManager pm = getEntityManager();
		try {
			if(!Dia.DiaDeLaSemana.get(date).equals(turno.getTurnoSemanal().getDiaDeLaSemana())) {
				throw new RuntimeException(
						"El dia de la semana " + turno.getTurnoSemanal().getDiaDeLaSemana() +
						" no coincide con el de la fecha " + date + " (" + Dia.DiaDeLaSemana.get(date) + ")");
			}
			date = Dia.clean(date);
			Turno turnoOriginal = getTurnoByDate(date, turno.getHorario(), pm);
			if(turnoOriginal != null) {
				if(turnoOriginal.getEstado() == null || turnoOriginal.getEstado().isDisponible()) {
					pm.deletePersistent(turnoOriginal);
				} else {
					throw new TurnoNoDisponibleException();
				}
			}
			turno.setFecha(date);
			pm.makePersistent(turno);
		} finally {
			pm.close();
		}
	}

	@Override
	public void addTurnoSemanal(TurnoSemanal tsem) {
		PersistenceManager pm = getEntityManager();
		try {
			tsem.setFechaInicio(Dia.clean(tsem.getFechaInicio()));
			pm.makePersistent(tsem);
		} finally {
			pm.close();
		}
	}
	
	@Override
	public void liberarTurno(Date date, Turno turno) {
		PersistenceManager pm = getEntityManager();
		try {
			date = Dia.clean(date);
			Turno turnoOriginal = getTurnoByDate(turno.getFecha(), turno.getHorario(), pm);
			if(turnoOriginal != null) {
				pm.deletePersistent(turnoOriginal);
			}
		} finally {
			pm.close();
		}
	}
	
	@Override
	public List<Turno> getTurnosAsignadosByDia(Date date) {
		PersistenceManager pm = getEntityManager();
		try {
			return selectTurnosByDia(date, pm);
		} finally {
			pm.close();
		}
	}

	@Override
	public List<TurnoSemanal> getTurnosSemanalesDesde(Date date) {
		PersistenceManager pm = getEntityManager();
		try {
			date = Dia.clean(date);
			Dia.DiaDeLaSemana dsem = Dia.DiaDeLaSemana.get(date);
			Query query = pm.newQuery(
					"select from " + TurnoSemanal.class.getName() +
					" where fechaInicio <= paramFechaInicio && " +
						"   diaDeLaSemanaAsString == paramDiaDeLaSemana");
			query.declareImports("import java.util.Date");
			query.declareParameters("Date paramFechaInicio, String paramDiaDeLaSemana");
			List<TurnoSemanal> list = (List<TurnoSemanal>) query.execute(date, dsem.toString());
			list.size();
			return list;
		} finally {
			pm.close();
		}
	}
	
	private PersistenceManager getEntityManager() {
		
		if(persistenceManagerFactory == null) {
			 persistenceManagerFactory = JDOHelper.getPersistenceManagerFactory("transactions-optional");
		}
		return persistenceManagerFactory.getPersistenceManager();
	}
	
	private Query selectFromTurnoWhere(String condicion, PersistenceManager manager) {
		return manager.newQuery("javax.jdo.query.JDOQL", "select from " + Turno.class.getName() + " where " + condicion);
	}
	
	private Turno getTurnoByDate(Date date, String horario, PersistenceManager pm) {
		Query query = selectFromTurnoWhere("fecha == paramFecha", pm);
		query.declareImports("import java.util.Date");
		query.declareParameters("Date paramFecha");
		List<Turno> turnos = (List<Turno>) query.execute(date);
		for(Turno t : turnos) {
			if(t.getHorario().equals(horario)) {
				return t;
			}
		}
		return null;
	}
	
	private List<Turno> selectTurnosByDia(Date date, PersistenceManager pm) {
		date = Dia.clean(date);
		Query query = selectFromTurnoWhere("fecha == paramFecha", pm);
		query.declareImports("import java.util.Date");
		query.declareParameters("Date paramFecha");
		List<Turno> turnos = (List<Turno>) query.execute(date);
		for (Turno turno : turnos) {
			turno.getTurnoSemanal();
		}
		return turnos;
	}

}
